package com.bluetrum.abmate.eq;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import android.os.Bundle;

import com.bluetrum.abmate.R;
import com.bluetrum.abmate.adapter.GridSpaceItemDecoration;
import com.bluetrum.abmate.adapter.RemoteEqAdapter;
import com.bluetrum.abmate.cmd.SimpleRequestCallback2;
import com.bluetrum.abmate.databinding.ActivityRemoteEqBinding;
import com.bluetrum.abmate.utils.Utils;
import com.bluetrum.abmate.viewmodels.SharedViewModel;
import com.bluetrum.abmate.cmd.SimpleRequestCallback;
import com.bluetrum.devicemanager.cmd.Command;
import com.bluetrum.devicemanager.cmd.Request;
import com.bluetrum.devicemanager.cmd.request.DeviceInfoRequest;
import com.bluetrum.devicemanager.cmd.request.EqRequest;
import com.bluetrum.devicemanager.models.RemoteEqSetting;
import com.bluetrum.utils.HexUtils;
import com.bluetrum.view.equalizerview.EqualizerView;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;

import dagger.hilt.android.AndroidEntryPoint;
import timber.log.Timber;

@AndroidEntryPoint
public class RemoteEqActivity extends AppCompatActivity
        implements RemoteEqAdapter.OnItemClickListener {

    private SharedViewModel mViewModel;

    private ActivityRemoteEqBinding binding;

    private RemoteEqAdapter mAdapter;
    private StaggeredGridLayoutManager mLayoutManager;
    private GridSpaceItemDecoration mItemDecoration;

    private static final int RECYCLER_VIEW_SPAN_COUNT = 3;

    private static final int ROW_SPACING = 4;
    private static final int COLUMN_SPACING = 4;

    private Byte currentEqMode;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mViewModel = new ViewModelProvider(this).get(SharedViewModel.class);
        binding = ActivityRemoteEqBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        setupEqualizerView();
        setupRecyclerView();

        mViewModel.getDeviceEqSetting().observe(this, this::eqSettingChanged); // 设备当前EQ设置
        mViewModel.getDeviceRemoteEqSettings().observe(this, this::remoteEqSettingsChanged);

        // 获取最新EQ配置
        mViewModel.sendRequest(new DeviceInfoRequest(Command.INFO_EQ_SETTING).requireInfo(Command.INFO_ALL_EQ_SETTINGS));
    }

    private void setupEqualizerView() {
        ArrayList<Integer> bands = new ArrayList<Integer>() {{
            add(8);
            add(31);
            add(62);
            add(125);
            add(250);
            add(500);
            add(1000);
            add(2000);
            add(4000);
            add(16000);
        }};

        binding.equalizerView.setBandListener(new EqualizerView.EventListener() {
            @Override
            public void onBandLevelChanged(int bandId, int progress, boolean fromUser) {
                if (fromUser) {
                    byte[] gains = getGains();

                    int level = binding.equalizerView.getBandLevel(bandId) - EqSetting.EQUALIZER_MAX_GAIN;
                    Timber.v("bandId: %s, level: %s, levels: %s", bandId, level, Arrays.toString(gains));

                    if (currentEqMode != null) {
                        RemoteEqSetting eqSetting = new RemoteEqSetting(currentEqMode, gains);
                        mAdapter.setCurrentEqSetting(eqSetting);

                        Request request = new EqRequest(currentEqMode, gains); // 第一个参数目前没用到
                        sendRequestAndWaitSuccess(request, null);
                    }
                }
            }

            @Override
            public void onStart(int bandId) {
                // empty
            }

            @Override
            public void onStop(int bandId) {
                // empty
            }
        });

        binding.equalizerView.setMotionEventSplittingEnabled(false); // 禁止多点
        binding.equalizerView.setOnlyUpdateWhenTouchUp(true);
        binding.equalizerView.setBands(bands);
        binding.equalizerView.setMax(EqSetting.EQUALIZER_MAX_GAIN * 2); // ±
        binding.equalizerView.draw();
    }

    private void setupRecyclerView() {
        int spanCount = RECYCLER_VIEW_SPAN_COUNT;
        mLayoutManager = new StaggeredGridLayoutManager(spanCount, StaggeredGridLayoutManager.VERTICAL);
        binding.recyclerView.setLayoutManager(mLayoutManager);

        mItemDecoration = new GridSpaceItemDecoration(spanCount, ROW_SPACING, COLUMN_SPACING);
        binding.recyclerView.addItemDecoration(mItemDecoration);

        mAdapter = new RemoteEqAdapter(this, null, spanCount);
        mAdapter.setOnItemClickListener(this);
        binding.recyclerView.setAdapter(mAdapter);
    }

    private void eqSettingChanged(RemoteEqSetting eqSetting) {
        // 检查有效性
        if (eqSetting != null) {
            currentEqMode = eqSetting.getMode();
            byte[] gains = eqSetting.getGains();

            binding.equalizerView.setEnabled(eqSetting.isCustom());

            Timber.v("EQ Hex: %s", HexUtils.bytesToHex(gains));
            showBandLevels(gains);
            mAdapter.setCurrentEqSetting(eqSetting);
        }
    }

    private void remoteEqSettingsChanged(List<RemoteEqSetting> eqSettings) {
        if (eqSettings != null) {
            mAdapter.setEqSettings(eqSettings);
        }
    }

    private byte[] getGains() {
        Map<String, Integer> levelsMap = binding.equalizerView.getBandLevels();
        ByteBuffer bb = ByteBuffer.allocate(levelsMap.size());
        // 按照Key排序，并按照格式{gain}放到ByteArray
        levelsMap.entrySet().stream().sorted(
                Comparator.comparingInt(entry -> Integer.parseInt(entry.getKey()))
        ).forEachOrdered(entry -> bb.put((byte) (entry.getValue().byteValue() - EqSetting.EQUALIZER_MAX_GAIN)));
        return bb.array();
    }

    private void showBandLevels(byte[] gains) {
        Map<String, Integer> map = IntStream.range(0, gains.length).boxed()
                .collect(HashMap::new, (m, v) -> {
                    m.put(Integer.toString(v), gains[v] + EqSetting.EQUALIZER_MAX_GAIN);
                }, (m1, m2) -> {

                });
        binding.equalizerView.setBandLevels(map);
    }

    @Override
    public void OnItemClick(RemoteEqSetting eqSetting) {
        final byte mode = eqSetting.getMode();
        final byte[] gains = eqSetting.getGains();
        showBandLevels(gains);
        mAdapter.setCurrentEqSetting(eqSetting);
        currentEqMode = mode;

        binding.equalizerView.setEnabled(eqSetting.isCustom());

        // Send request
        Request request = new EqRequest(mode, gains);
        sendRequestAndWaitSuccess(request, null);
    }

    /* Request */

    private void startWaitingResponse() {
//        binding.progressIndicator.setVisibility(View.VISIBLE);
//        binding.scrollView.setEnabled(false); // todo: 没用
    }

    private void stopWaitingResponse() {
//        binding.progressIndicator.setVisibility(View.GONE);
//        binding.scrollView.setEnabled(true); // todo: 没用
    }

    /*
    统一处理返回值Boolean的Request，并提示可能的失败和超时
     */
    private void sendRequestAndWaitSuccess(@NonNull final Request request,
                                           @Nullable SimpleRequestCallback2 callback2) {
        // todo: 加上发送等待画面
        startWaitingResponse();

        mViewModel.sendRequest(request, new SimpleRequestCallback2() {
            @Override
            public void onComplete(boolean result) {
                Timber.d("sendRequest result = %s", result);

                if (result) {
                    Utils.showToast(RemoteEqActivity.this, R.string.request_succeeded);
                } else {
                    Utils.showToast(RemoteEqActivity.this, R.string.request_failed);
                }

                // todo: 解除发送等待
                stopWaitingResponse();

                if (callback2 != null) {
                    callback2.onComplete(result);
                }
            }

            @Override
            public void onTimeout() {
                Timber.w("Request timeout");
                Utils.showToast(RemoteEqActivity.this, R.string.request_timeout);

                // todo: 解除发送等待
                stopWaitingResponse();

                if (callback2 != null) {
                    callback2.onTimeout();
                }
            }
        });
    }

}